#include "../test_impl.h"

#include "../../../include/component_module.h"
#include "../../../include/mutex.h"
#include "../../../include/tools.h"

#include <sstream>
#include <list>

namespace Test
{


  class MyReceiver
    : public IReceiverImpl
  {
  public:
    MyReceiver()
      : Id(0)
    {
      RefObjPtr<IServiceLocator> ServiceLocator = Tools::GetServiceLocator();
      if (!ServiceLocator.Get())
        return;
      RefObjPtr<IBase> WriterInst;
      if (ServiceLocator->GetService(BOSS_UUID_OF(IWriter), WriterInst.GetPPtr()) != rcOk)
        return;
      Writer = WriterInst;
    }
    void SetId(unsigned long id)
    {
      Id = id;
    }

  protected:
    virtual void ProcessMsg(IMessage *msg)
    {
      RefObjPtr<IMessage> Msg(msg);
      if (!Msg.Get())
        return;
      if (!Writer.Get())
        return;
      std::stringstream Io;
      Io << "ReceiverId = " << Id << " Msg = " << Msg->Get();
      Writer->Write(Io.str().c_str());
    }

  private:
    unsigned long Id;
    RefObjQIPtr<IWriter> Writer;
  };

  class ITestServiceImpl
    : public CoClassBase
        <
        TL::TypeListAdapter
          <
            ITestService
          >
        >
  {
  public:
    BOSS_DECLARE_STR_CLSID(TEST_ITESTRECVSERVICEIMPL)

    ITestServiceImpl()
    {
    }

    // ITestService
    virtual TResult BOSS_CALL_TYPE Start()
    {
      ISyncObject Lock(GetSynObj());
      try
      {
        RefObjPtr<IServiceLocator> ServiceLocator = Tools::GetServiceLocator();
        if (!ServiceLocator.Get())
          return rcFail;
        RefObjPtr<IBase> MsgMgrInst;
        if (ServiceLocator->GetService(BOSS_UUID_OF(IMessageMgr), MsgMgrInst.GetPPtr()) != rcOk)
          return rcFail;
        RefObjQIPtr<IMessageMgr> MsgMgr(MsgMgrInst);
        if (!MsgMgr.Get())
          return rcFail;
        RecvPool NewPool;
        for (unsigned long i = 0 ; i < 20 ; ++i)
        {
          RefObjPtr<MyReceiver> Recv(IBaseImpl<MyReceiver>::Create());
          Recv->SetId(i);
          NewPool.push_back(Recv);
        }
        Receivers = NewPool;
        for (RecvPool::iterator i = Receivers.begin() ; i != Receivers.end() ; ++i)
          MsgMgr->Subscribe(i->Get());
      }
      catch (std::exception &)
      {
        return rcFail;
      }
      return rcOk;
    }
    virtual TResult BOSS_CALL_TYPE Stop()
    {
      try
      {
        ISyncObject Lock(GetSynObj());
        RefObjPtr<IServiceLocator> ServiceLocator = Tools::GetServiceLocator();
        if (!ServiceLocator.Get())
          return rcFail;
        RefObjPtr<IBase> MsgMgrInst;
        if (ServiceLocator->GetService(BOSS_UUID_OF(IMessageMgr), MsgMgrInst.GetPPtr()) != rcOk)
          return rcFail;
        RefObjQIPtr<IMessageMgr> MsgMgr(MsgMgrInst);
        if (!MsgMgr.Get())
          return rcFail;
        for (RecvPool::iterator i = Receivers.begin() ; i != Receivers.end() ; ++i)
          MsgMgr->Unsubscribe(i->Get());
        Receivers.clear();
      }
      catch (std::exception &)
      {
        return rcFail;
      }
      return rcOk;
    }

  private:
    typedef RefObjPtr<IReceiver> IReceiverPtr;
    typedef std::list<IReceiverPtr> RecvPool;
    RecvPool Receivers;
  };

  typedef TL::TypeListAdapter
  <
    ITestServiceImpl
  >
  ExportTypeList;
}

BOSS_DECLARE_MODULE_ENTRY_POINT
(
  "TestComponent2",
  348f32f8-c52c-4621-b1e9-ec173a0f0d29,
  Boss::Mutex,
  Test::ExportTypeList
)
